home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
amok_lha
/
amok22.lha
/
CrossRef
/
Cross.mod
< prev
next >
Wrap
Text File
|
1993-08-15
|
17KB
|
515 lines
(*---------------------------------------------------------------------------
:Program. Cross.mod
:Author. Andreas Pahl
:Address. Zikadenweg 22, D-1000 Berlin 19
:Phone. (0)30/302 55 37
:Version. 1.00
:Date. 13.Juli 1989
:Copyright. PD
:Language. Modula
:Translator. M2Amiga v3.2d
:Contents. CrossReference-Lister
:Bugs. Erkennt bei Zuweisung von 0C C als Bezeichner
---------------------------------------------------------------------------*)
(*
Ideen zur Erweiterung:
----------------------
- Ausgabedatei wählen können
- Zeilenbreite variabel
- Anzeigen, wo der Bezeichner definiert ist (Welches Modul, welche
Prozedur)
- Was er alles anzeigen soll, irgendwie vom Benutzer wählen lassen
(aber mit Voreinstellung)
- Mit Modlist verbinden
- Schachtelungstiefe ausgeben
- Smart-Linker auf Sourceebene
- Zu jeder Prozedur alle Bezeichner herausschreiben, die in ihr
verwendet, aber nicht deklariert werden. Hilfreich für Programm-
modifikationen und gegen unerwünschte Seiteneffekte
*)
MODULE Cross;
FROM FileSystem IMPORT Lookup, Close, ReadChar, File, Response, WriteChar,
WriteBytes;
FROM InOut IMPORT ReadString, WriteLn, WriteString, Write;
FROM Arts IMPORT BreakPoint;
FROM SYSTEM IMPORT ADR;
FROM Strings IMPORT Compare, Length;
FROM ASCII IMPORT eol,cr,lf;
FROM Arguments IMPORT GetArg, NumArgs;
FROM Conversions IMPORT ValToStr;
(* AMOK-Module *)
FROM MemSystem IMPORT Allocate, Deallocate;
TYPE
(* Erklärung der Datenstruktur siehe Dokumentation *)
ListPointer = POINTER TO ListNode;
ListNode = RECORD
Nummer : CARDINAL; (* Zeilennummer *)
Next : ListPointer;
END;
Trie = POINTER TO Node;
Node = RECORD
Buchstabe : CHAR;
Typ : CHAR; (* Typ des Bezeichners *)
Anzahl : CARDINAL; (* Häufigkeit des Bezeichners *)
Erster, (* Liste der Zeilennummern *)
Letzter : ListPointer;
Wortende : BOOLEAN; (* Markiert Wortende im Trie *)
horizontal,
vertikal : Trie;
END;
String = ARRAY [0..80] OF CHAR;
VAR
Ueberschrift, (* Length möchte Variablen *)
Unterstreichen,
Wort : String; (* enthält aktuelles Wort *)
Ende : BOOLEAN; (* TRUE = Ende eines Wortes *)
OutputFile, (* Ausgabe-File *)
QuellFile : File; (* zu untersuchende Source *)
OutputName, (* Dos-Name des Ausgabe-Files *)
DosName : String; (* Dos-Name des Sourcefiles *)
Zeichen : CHAR; (* gelesenes Zeichen *)
Baum : Trie; (* Da wird alles gespeichert *)
ZeilenNummer : CARDINAL;
Len : INTEGER; (* Für GetArg *)
BezeichnerTyp : CHAR;
actual : LONGINT; (* Für WriteBytes *)
AltesZeichen : CHAR; (* Das vorhergehende Zeichen *)
(* muß gespeichert werden, um *)
(* Kommentare zu erkennen *)
PROCEDURE LiesZeichen(VAR Zeichen : CHAR);
(* Liest ein Zeichen aus dem File aus, übergeht Kommentare und Strings *)
(* und erkennt das Wortende. *)
PROCEDURE Read ( VAR Zeichen : CHAR );
(* Liest ein Zeichen aus dem QuellFile und inkrementiert den
Zeilenzähler gegebenenfalls. *)
BEGIN
ReadChar(QuellFile,Zeichen);
IF (Zeichen = eol) OR (Zeichen = cr) THEN
INC(ZeilenNummer);
END;
END Read;
BEGIN
Read(Zeichen);
(* Strings sollen überlesen werden *)
IF Zeichen = '"' THEN
REPEAT
Read(Zeichen);
UNTIL Zeichen = '"';
Read(Zeichen);
END;
IF Zeichen = "'" THEN
REPEAT
Read(Zeichen);
UNTIL Zeichen = "'";
Read(Zeichen);
END;
(* Kommentare sollen auch überlesen werden *)
IF (Zeichen = "*") AND (AltesZeichen = "(") THEN
REPEAT
AltesZeichen := Zeichen;
Read(Zeichen)
UNTIL (Zeichen = ")") AND (AltesZeichen = "*");
END;
(* Tritt ein Nichtbuchstabe auf, ist das Wort beendet *)
IF NOT ( ( (Zeichen >= 'a') AND (Zeichen <= 'z') )
OR ( (Zeichen >= 'A') AND (Zeichen <= 'Z') ) ) THEN
Ende := TRUE;
END;
AltesZeichen := Zeichen;
END LiesZeichen;
PROCEDURE Insert(VAR Knoten : Trie; level : CARDINAL);
VAR
NeuerKnoten : Trie; (* Knoten zum Einfügen in *)
(* den Trie *)
NeuerListNode : ListPointer; (* Knoten zum Einfügen in die *)
(* Liste der Zeilennummern *)
PROCEDURE Wandern();
(* Wandert im Baum eine Ebene tiefer, falls nicht das Wortende *)
(* detektiert wurde. Zusätzlich wird der Bezeichnertyp bestimmt. *)
BEGIN
LiesZeichen(Zeichen);
IF Ende = FALSE THEN
Insert(Knoten^.vertikal,level+1);
ELSE
Knoten^.Wortende := TRUE; (* Das Wort ist beendet, am *)
(* aktuellen Knoten wird dies *)
(* markiert. *)
Wort[level+1] := 0C;
IF Knoten^.Anzahl = 0 THEN (* Wenn das Wort zum ersten *)
Knoten^.Typ := BezeichnerTyp; (* auftaucht, wird der Typ *)
END; (* des Bezeichners gespeichert*)
(* Jetzt wird getestet, ob das*)
(* beendete Wort, den aktu- *)
(* ellen Bezeichnertyp ändert *)
IF Compare(Wort,0,Length(Wort),"FROM",TRUE) = 0 THEN
BezeichnerTyp := "F";
END;
IF Compare(Wort,0,Length(Wort),"IMPORT",TRUE) = 0 THEN
BezeichnerTyp := "I";
END;
IF Compare(Wort,0,Length(Wort),"MODULE",TRUE) = 0 THEN
BezeichnerTyp := "M";
END;
IF Compare(Wort,0,Length(Wort),"PROCEDURE",TRUE) = 0 THEN
BezeichnerTyp := "P";
END;
IF Compare(Wort,0,Length(Wort),"CONST",TRUE) = 0 THEN
BezeichnerTyp := "C";
END;
IF Compare(Wort,0,Length(Wort),"TYPE",TRUE) = 0 THEN
BezeichnerTyp := "T";
END;
IF Compare(Wort,0,Length(Wort),"VAR",TRUE) = 0 THEN
BezeichnerTyp := "V";
END;
IF Compare(Wort,0,Length(Wort),"BEGIN",TRUE) = 0 THEN
BezeichnerTyp := "B";
END;
Knoten^.Anzahl := Knoten^.Anzahl + 1;
(* Zeilennummer in die Liste *)
(* der Zeilennummern einfügen *)
Allocate(NeuerListNode,SIZE(ListPointer));
NeuerListNode^.Nummer := ZeilenNummer;
NeuerListNode^.Next := NIL;
IF Knoten^.Erster = NIL THEN
Knoten^.Erster := NeuerListNode;
Knoten^.Letzter := NeuerListNode;
ELSE
Knoten^.Letzter^.Next := NeuerListNode;
Knoten^.Letzter := NeuerListNode;
END;
END;
END Wandern;
BEGIN
IF Knoten = NIL THEN (* Wenn Baum leer, *)
Allocate(NeuerKnoten,SIZE(Node)); (* dann Wurzel generieren *)
NeuerKnoten^.Wortende := FALSE;
NeuerKnoten^.Anzahl := 0;
NeuerKnoten^.Buchstabe := Zeichen;
NeuerKnoten^.Erster := NIL;
NeuerKnoten^.Letzter := NIL;
Wort[level] := Zeichen;
Knoten := NeuerKnoten;
Wandern;
ELSIF ORD(Knoten^.Buchstabe) > ORD(Zeichen) THEN
(* Wenn Buchstabe > Zeichen *)
Allocate(NeuerKnoten,SIZE(Node));
NeuerKnoten^.Wortende := FALSE;
NeuerKnoten^.Anzahl := 0;
NeuerKnoten^.Buchstabe := Zeichen;
NeuerKnoten^.Erster := NIL;
NeuerKnoten^.Letzter := NIL;
Wort[level] := Zeichen;
NeuerKnoten^.horizontal := Knoten; (* dann neuen Knoten vor dem *)
Knoten := NeuerKnoten; (* alten horizontal einfügen *)
Wandern;
ELSIF ORD(Knoten^.Buchstabe) < ORD(Zeichen) THEN
(* Wenn Buchstabe < Zeichen *)
(* dann einen Knoten horizon- *)
(* tal weiterwandern *)
Insert(Knoten^.horizontal,level);
ELSE (* Wenn Buchstabe = Zeichen *)
Wort[level] := Zeichen; (* dann einen Knoten vertikal *)
Wandern; (* weiterwandern *)
END;
END Insert;
PROCEDURE NeueZeile;
(* Geht beim OutputFile auf die nächste Zeile *)
BEGIN
WriteChar(OutputFile,cr);
WriteChar(OutputFile,lf);
END NeueZeile;
PROCEDURE WriteCard(Val,Digits:CARDINAL);
(* Wandelt einen CARDINAL in einen String und schreibt ihn ins OutputFile *)
VAR
Error : BOOLEAN;
Str : ARRAY [0..35] OF CHAR;
BEGIN
ValToStr(Val,FALSE,Str,10,Digits," ",Error);
IF NOT Error THEN
WriteBytes(OutputFile,ADR(Str),Length(Str),actual);
END;
END WriteCard;
PROCEDURE PrintTrie(Knoten : Trie; level : CARDINAL);
(* Wandert rekursiv durch den Trie und gibt die Worte aus *)
VAR
Zaehler : CARDINAL; (* Zählt die Nummern pro *)
(* Ausgabezeile *)
pointer : ListPointer; (* Zum Durchwandern der Liste *)
(* der Zeilennummern *)
PROCEDURE ReserviertesWort(Wort : String) : BOOLEAN;
(* Überprüft, ob das übergebene Wort ein reservierter Bezeichner ist *)
CONST
Eintraege = 73; (* Anzahl der Eintraege in ResWort *)
VAR
(* Darin sind die reservierten Bezeichner abgelegt *)
ResWort : ARRAY [1..Eintraege] OF String;
Index : CARDINAL; (* Indexzähler für ResWort *)
Reserviert : BOOLEAN;
wort : String; (* Length möchte einen call- *)
(* by-reference, ich übergebe *)
(* aber nur call-by-value *)
BEGIN
(* Alle Reservierten Worte und Vordefinierten Bezeichner von Seite 5-15
des Handbuches zur Version 3.2d. Zwei fehlen aber in der Auflistung :
FOR als Reserviertes Wort
VAL als Vordefinierter Bezeichner
*)
ResWort[ 1]:="AND"; ResWort[21]:="LOOP";
ResWort[ 2]:="ARRAY"; ResWort[22]:="MOD";
ResWort[ 3]:="BEGIN"; ResWort[23]:="MODULE";
ResWort[ 4]:="BY"; ResWort[24]:="NOT";
ResWort[ 5]:="CASE"; ResWort[25]:="OF";
ResWort[ 6]:="CONST"; ResWort[26]:="OR";
ResWort[ 7]:="DEFINITION"; ResWort[27]:="POINTER";
ResWort[ 8]:="DIV"; ResWort[28]:="PROCEDURE";
ResWort[ 9]:="DO"; ResWort[29]:="QUALIFIED";
ResWort[10]:="ELSE"; ResWort[30]:="RECORD";
ResWort[11]:="ELSIF"; ResWort[31]:="REPEAT";
ResWort[12]:="END"; ResWort[32]:="RETURN";
ResWort[13]:="EXIT"; ResWort[33]:="SET";
ResWort[14]:="EXPORT"; ResWort[34]:="THEN";
ResWort[15]:="FOR"; ResWort[35]:="TO";
ResWort[16]:="FROM"; ResWort[36]:="TYPE";
ResWort[17]:="IF"; ResWort[37]:="UNTIL";
ResWort[18]:="IMPLEMENTATION";ResWort[38]:="VAR";
ResWort[19]:="IMPORT"; ResWort[39]:="WHILE";
ResWort[20]:="IN"; ResWort[40]:="WITH";
ResWort[41]:="BPOINTER"; ResWort[51]:="DEC";
ResWort[42]:="CODE"; ResWort[52]:="EXCL";
ResWort[43]:="FORWARD"; ResWort[53]:="FALSE";
ResWort[44]:="REM"; ResWort[54]:="FLOAT";
ResWort[45]:="ABS"; ResWort[55]:="HALT";
ResWort[46]:="BOOLEAN"; ResWort[56]:="HIGH";
ResWort[47]:="CAP"; ResWort[57]:="INC";
ResWort[48]:="CARDINAL"; ResWort[58]:="INCL";
ResWort[49]:="CHAR"; ResWort[59]:="INTEGER";
ResWort[50]:="CHR"; ResWort[60]:="LONGCARD";
ResWort[61]:="LONGINT"; ResWort[66]:="ODD";
ResWort[62]:="LONGREAL"; ResWort[67]:="ORD";
ResWort[63]:="MAX"; ResWort[68]:="PROC";
ResWort[64]:="MIN"; ResWort[69]:="REAL";
ResWort[65]:="NIL"; ResWort[70]:="SIZE";
ResWort[71]:="TRUE"; ResWort[72]:="TRUNC";
ResWort[73]:="VAL";
wort := Wort;
Reserviert := FALSE;
Index := 1;
WHILE (Index <= Eintraege) AND NOT Reserviert DO
Reserviert := (Compare(wort,0,Length(wort),ResWort[Index],TRUE) = 0);
INC(Index);
END;
RETURN(Reserviert);
END ReserviertesWort;
BEGIN
IF Knoten^.Wortende = TRUE THEN
Wort[level] := Knoten^.Buchstabe;
Wort[level+1] := 0C;
IF NOT ReserviertesWort(Wort) THEN (* Ausgabe des Wortes usw. *)
WriteBytes(OutputFile,ADR(Wort),Length(Wort),actual);
WriteCard(Knoten^.Anzahl,25-level);
WriteBytes(OutputFile,ADR(" "),3,actual);
WriteChar(OutputFile,Knoten^.Typ);
WriteChar(OutputFile," ");
Zaehler := 0;
pointer := Knoten^.Erster;
REPEAT
IF Zaehler = 8 THEN
Zaehler := 0;
NeueZeile;
WriteBytes(OutputFile,ADR(" "),31,actual);
END;
WriteCard(pointer^.Nummer,5);
INC(Zaehler);
pointer := pointer^.Next;
UNTIL pointer = NIL;
NeueZeile;
END;
END;
IF Knoten^.vertikal # NIL THEN (* Es geht doch nichts über *)
Wort[level] := Knoten^.Buchstabe; (* eine schöne Rekursion *)
PrintTrie(Knoten^.vertikal,level+1);
END;
IF Knoten^.horizontal # NIL THEN
Wort[level] := Knoten^.Buchstabe;
PrintTrie(Knoten^.horizontal,level);
END;
END PrintTrie;
PROCEDURE Initialisierung();
(* Schreiben des Headers und Öffnen der Files *)
BEGIN
WriteLn;
WriteString("CrossReference-Lister V1.00 © Andreas Pahl");
WriteLn;
WriteLn;
WriteString("Sourcelisting : ");
IF NumArgs() >= 1 THEN (* Source als Argument übergeben? *)
GetArg(1,DosName,Len);
WriteString(DosName);
WriteLn;
ELSE (* sonst abfragen *)
WriteLn;
WriteLn;
WriteString("in>");
ReadString(DosName);
END;
Lookup(QuellFile,DosName,1024,FALSE);
IF QuellFile.res # done THEN
WriteLn;
WriteString("Datei konnte nicht geöffnet werden.");
WriteLn;
HALT;
END;
WriteLn;
WriteLn;
WriteString("Ausgabedatei : (prt: für Ausgabe auf Drucker)");
WriteLn;
WriteLn;
WriteString("out>");
ReadString(OutputName);
Lookup(OutputFile,OutputName,1024,TRUE);
IF OutputFile.res # done THEN
WriteLn;
WriteString("Datei konnte nicht geöffnet werden.");
WriteLn;
Close(QuellFile);
HALT;
END;
END Initialisierung;
BEGIN (* Hauptprogramm *)
Initialisierung;
Allocate(Baum,SIZE(Node));
Baum := NIL;
Ende := FALSE;
ZeilenNummer := 1;
LOOP
LiesZeichen(Zeichen);
IF QuellFile.eof THEN
EXIT;
END;
IF NOT Ende THEN
Insert(Baum,0);
END;
Ende := FALSE;
END;
Close(QuellFile);
(* Ausgabe der Überschrift der Tabelle *)
(* Warum braucht Length bloß einen call-by-reference ??? *)
Ueberschrift := "Bezeichner Anzahl Typ Zeilen";
Unterstreichen := "-----------------------------------------------------------------------";
WriteBytes(OutputFile,ADR(Ueberschrift),Length(Ueberschrift),actual);
NeueZeile;
WriteBytes(OutputFile,ADR(Unterstreichen),Length(Unterstreichen),actual);
NeueZeile;
PrintTrie(Baum,0);
Close(OutputFile);
END Cross.